#include "GLViewImpl.h"

struct keyCodeItem
{
	int glfwKeyCode;
	EventKeyboard::KeyCode keyCode;
};

static std::unordered_map<int, EventKeyboard::KeyCode> g_keyCodeMap;

static keyCodeItem g_keyCodeStructArray[] = {
	/* The unknown key */
	//		{ GLFW_KEY_UNKNOWN, EventKeyboard::KeyCode::KEY_NONE },

	/* Printable keys */
		{ GGEK_SPACE, EventKeyboard::KeyCode::KEY_SPACE },
		{ GGEK_APOSTROPHE, EventKeyboard::KeyCode::KEY_APOSTROPHE },
		{ GGEK_COMMA, EventKeyboard::KeyCode::KEY_COMMA },
		{ GGEK_MINUS, EventKeyboard::KeyCode::KEY_MINUS },
		{ GGEK_PERIOD, EventKeyboard::KeyCode::KEY_PERIOD },
		{ GGEK_SLASH, EventKeyboard::KeyCode::KEY_SLASH },
		{ GGEK_0, EventKeyboard::KeyCode::KEY_0 },
		{ GGEK_1, EventKeyboard::KeyCode::KEY_1 },
		{ GGEK_2, EventKeyboard::KeyCode::KEY_2 },
		{ GGEK_3, EventKeyboard::KeyCode::KEY_3 },
		{ GGEK_4, EventKeyboard::KeyCode::KEY_4 },
		{ GGEK_5, EventKeyboard::KeyCode::KEY_5 },
		{ GGEK_6, EventKeyboard::KeyCode::KEY_6 },
		{ GGEK_7, EventKeyboard::KeyCode::KEY_7 },
		{ GGEK_8, EventKeyboard::KeyCode::KEY_8 },
		{ GGEK_9, EventKeyboard::KeyCode::KEY_9 },
		{ GGEK_SEMICOLON, EventKeyboard::KeyCode::KEY_SEMICOLON },
		{ GGEK_EQUALS, EventKeyboard::KeyCode::KEY_EQUAL },
		{ GGEK_A, EventKeyboard::KeyCode::KEY_A },
		{ GGEK_B, EventKeyboard::KeyCode::KEY_B },
		{ GGEK_C, EventKeyboard::KeyCode::KEY_C },
		{ GGEK_D, EventKeyboard::KeyCode::KEY_D },
		{ GGEK_E, EventKeyboard::KeyCode::KEY_E },
		{ GGEK_F, EventKeyboard::KeyCode::KEY_F },
		{ GGEK_G, EventKeyboard::KeyCode::KEY_G },
		{ GGEK_H, EventKeyboard::KeyCode::KEY_H },
		{ GGEK_I, EventKeyboard::KeyCode::KEY_I },
		{ GGEK_J, EventKeyboard::KeyCode::KEY_J },
		{ GGEK_K, EventKeyboard::KeyCode::KEY_K },
		{ GGEK_L, EventKeyboard::KeyCode::KEY_L },
		{ GGEK_M, EventKeyboard::KeyCode::KEY_M },
		{ GGEK_N, EventKeyboard::KeyCode::KEY_N },
		{ GGEK_O, EventKeyboard::KeyCode::KEY_O },
		{ GGEK_P, EventKeyboard::KeyCode::KEY_P },
		{ GGEK_Q, EventKeyboard::KeyCode::KEY_Q },
		{ GGEK_R, EventKeyboard::KeyCode::KEY_R },
		{ GGEK_S, EventKeyboard::KeyCode::KEY_S },
		{ GGEK_T, EventKeyboard::KeyCode::KEY_T },
		{ GGEK_U, EventKeyboard::KeyCode::KEY_U },
		{ GGEK_V, EventKeyboard::KeyCode::KEY_V },
		{ GGEK_W, EventKeyboard::KeyCode::KEY_W },
		{ GGEK_X, EventKeyboard::KeyCode::KEY_X },
		{ GGEK_Y, EventKeyboard::KeyCode::KEY_Y },
		{ GGEK_Z, EventKeyboard::KeyCode::KEY_Z },
		{ GGEK_LBRACKET, EventKeyboard::KeyCode::KEY_LEFT_BRACKET },
		{ GGEK_BACKSLASH, EventKeyboard::KeyCode::KEY_BACK_SLASH },
		{ GGEK_RBRACKET, EventKeyboard::KeyCode::KEY_RIGHT_BRACKET },
		{ GGEK_GRAVE, EventKeyboard::KeyCode::KEY_GRAVE },
		// 		{ GGEK_WORLD_1, EventKeyboard::KeyCode::KEY_GRAVE },
		// 		{ GGEK_WORLD_2, EventKeyboard::KeyCode::KEY_NONE },
		/* Function keys */
		{ GGEK_ESCAPE, EventKeyboard::KeyCode::KEY_ESCAPE },
		{ GGEK_ENTER, EventKeyboard::KeyCode::KEY_ENTER },
		{ GGEK_TAB, EventKeyboard::KeyCode::KEY_TAB },
		{ GGEK_BACKSPACE, EventKeyboard::KeyCode::KEY_BACKSPACE },
		{ GGEK_INSERT, EventKeyboard::KeyCode::KEY_INSERT },
		{ GGEK_DELETE, EventKeyboard::KeyCode::KEY_DELETE },
		{ GGEK_RIGHT, EventKeyboard::KeyCode::KEY_RIGHT_ARROW },
		{ GGEK_LEFT, EventKeyboard::KeyCode::KEY_LEFT_ARROW },
		{ GGEK_DOWN, EventKeyboard::KeyCode::KEY_DOWN_ARROW },
		{ GGEK_UP, EventKeyboard::KeyCode::KEY_UP_ARROW },
		{ GGEK_PGUP, EventKeyboard::KeyCode::KEY_PG_UP },
		{ GGEK_PGDN, EventKeyboard::KeyCode::KEY_PG_DOWN },
		{ GGEK_HOME, EventKeyboard::KeyCode::KEY_HOME },
		{ GGEK_END, EventKeyboard::KeyCode::KEY_END },
		{ GGEK_CAPSLOCK, EventKeyboard::KeyCode::KEY_CAPS_LOCK },
		{ GGEK_SCROLLLOCK, EventKeyboard::KeyCode::KEY_SCROLL_LOCK },
		{ GGEK_NUMLOCK, EventKeyboard::KeyCode::KEY_NUM_LOCK },
		//		{ GGEK_PRINTSCREEN, EventKeyboard::KeyCode::KEY_PRINT },
		{ GGEK_PAUSE, EventKeyboard::KeyCode::KEY_PAUSE },
		{ GGEK_F1, EventKeyboard::KeyCode::KEY_F1 },
		{ GGEK_F2, EventKeyboard::KeyCode::KEY_F2 },
		{ GGEK_F3, EventKeyboard::KeyCode::KEY_F3 },
		{ GGEK_F4, EventKeyboard::KeyCode::KEY_F4 },
		{ GGEK_F5, EventKeyboard::KeyCode::KEY_F5 },
		{ GGEK_F6, EventKeyboard::KeyCode::KEY_F6 },
		{ GGEK_F7, EventKeyboard::KeyCode::KEY_F7 },
		{ GGEK_F8, EventKeyboard::KeyCode::KEY_F8 },
		{ GGEK_F9, EventKeyboard::KeyCode::KEY_F9 },
		{ GGEK_F10, EventKeyboard::KeyCode::KEY_F10 },
		{ GGEK_F11, EventKeyboard::KeyCode::KEY_F11 },
		{ GGEK_F12, EventKeyboard::KeyCode::KEY_F12 },
// 		{ GGEK_F13, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F14, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F15, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F16, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F17, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F18, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F19, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F20, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F21, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F22, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F23, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F24, EventKeyboard::KeyCode::KEY_NONE },
// 		{ GGEK_F25, EventKeyboard::KeyCode::KEY_NONE },
		{ GGEK_NUMPAD0, EventKeyboard::KeyCode::KEY_0 },
		{ GGEK_NUMPAD1, EventKeyboard::KeyCode::KEY_1 },
		{ GGEK_NUMPAD2, EventKeyboard::KeyCode::KEY_2 },
		{ GGEK_NUMPAD3, EventKeyboard::KeyCode::KEY_3 },
		{ GGEK_NUMPAD4, EventKeyboard::KeyCode::KEY_4 },
		{ GGEK_NUMPAD5, EventKeyboard::KeyCode::KEY_5 },
		{ GGEK_NUMPAD6, EventKeyboard::KeyCode::KEY_6 },
		{ GGEK_NUMPAD7, EventKeyboard::KeyCode::KEY_7 },
		{ GGEK_NUMPAD8, EventKeyboard::KeyCode::KEY_8 },
		{ GGEK_NUMPAD9, EventKeyboard::KeyCode::KEY_9 },
		{ GGEK_PERIOD, EventKeyboard::KeyCode::KEY_PERIOD },
		{ GGEK_DIVIDE, EventKeyboard::KeyCode::KEY_KP_DIVIDE },
		{ GGEK_MULTIPLY, EventKeyboard::KeyCode::KEY_KP_MULTIPLY },
		{ GGEK_SUBTRACT, EventKeyboard::KeyCode::KEY_KP_MINUS },
		{ GGEK_ADD, EventKeyboard::KeyCode::KEY_KP_PLUS },
		{ GGEK_ENTER, EventKeyboard::KeyCode::KEY_ENTER },
//		{ GGEK_ENTER, EventKeyboard::KeyCode::KEY_KP_ENTER },
//		{ GGEK_EQUAL, EventKeyboard::KeyCode::KEY_EQUAL },
		{ GGEK_SHIFT, EventKeyboard::KeyCode::KEY_LEFT_SHIFT },
		{ GGEK_CTRL, EventKeyboard::KeyCode::KEY_LEFT_CTRL },
		{ GGEK_ALT, EventKeyboard::KeyCode::KEY_LEFT_ALT },
//		{ GGEK_LEFT_SUPER, EventKeyboard::KeyCode::KEY_HYPER },
		{ GGEK_SHIFT, EventKeyboard::KeyCode::KEY_RIGHT_SHIFT },
		{ GGEK_CTRL, EventKeyboard::KeyCode::KEY_RIGHT_CTRL },
		{ GGEK_ALT, EventKeyboard::KeyCode::KEY_RIGHT_ALT },
//		{ GGEK_RIGHT_SUPER, EventKeyboard::KeyCode::KEY_HYPER },
//		{ GGEK_MENU, EventKeyboard::KeyCode::KEY_MENU },
//		{ GGEK_LAST, EventKeyboard::KeyCode::KEY_NONE }
};

bool GLViewImpl::init(const std::string& viewName, Rect rect)
{
	g_keyCodeMap.clear();
	for (auto& item : g_keyCodeStructArray)
	{
		g_keyCodeMap[item.glfwKeyCode] = item.keyCode;
	}

	setViewName(viewName);

	setFrameSize(rect.size.width, rect.size.height);

	return true;
}


HWND GLViewImpl::getWin32Window()
{
	return (HWND)gge::System_GetState(gge::GGE_STATE_SYS_VAL::GGE_HWND);
}

void GLViewImpl::setCursorVisible(bool visible)
{
	gge::System_SetState(gge::GGE_STATE_BOOL::GGE_HIDEMOUSE, false);
}

void GLViewImpl::setViewName(const std::string& viewname)
{
	GLView::setViewName(viewname);
	gge::System_SetState(gge::GGE_STATE_CHAR::GGE_TITLE, viewname.c_str());
}

void GLViewImpl::setFrameSize(float width, float height)
{
	GLView::setFrameSize(width, height);
	gge::System_SetState(gge::GGE_STATE_INT::GGE_SCREENWIDTH, (int)width);
	gge::System_SetState(gge::GGE_STATE_INT::GGE_SCREENHEIGHT, (int)height);
}


void GLViewImpl::setScissorInPoints(float x, float y, float w, float h)
{
//	gge::Graph_SetClipping(x, y, w, h);
	gge::ggeClipRect r;
	r.x = x;
	r.y = y;
	r.width = w;
	r.height = h;
	gge::Graph_PushClipRect(r);
//	gge::Graph_Clear(0x00101010);
}


void GLViewImpl::pollEvents()
{
	static bool isLdown = false; isLdown = gge::Input_IsMouseDown(GGEK_LBUTTON);
	static bool isLup = false; isLup = gge::Input_IsMouseUp(GGEK_LBUTTON);
	static bool isRdown = false; isRdown = gge::Input_IsMouseDown(GGEK_RBUTTON);
	static bool isRup = false; isRup = gge::Input_IsMouseUp(GGEK_RBUTTON);
	static bool isMdown = false; isMdown = gge::Input_IsMouseDown(GGEK_MBUTTON);
	static bool isMup = false; isMup = gge::Input_IsMouseUp(GGEK_MBUTTON);

	static float _mouseX, _mouseY, cursorX, cursorY;
	static bool isMouseMove; isMouseMove =
		(std::abs(gge::Input_GetMousePosX() - _mouseX) > FLT_EPSILON) ||
		(std::abs(gge::Input_GetMousePosY() - _mouseY) > FLT_EPSILON);

	if (isMouseMove)
	{
		_mouseX = gge::Input_GetMousePosX();
		_mouseY = gge::Input_GetMousePosY();
		cursorX = (_mouseX - _viewPortRect.origin.x) / _scaleX;
		cursorY = (_viewPortRect.origin.y + _viewPortRect.size.height - _mouseY) / _scaleY;
	}

	if (isLdown)
	{
		_captured = true;
		if (this->getViewPortRect().equals(Rect::ZERO) || this->getViewPortRect().containsPoint(Vec2(_mouseX, _mouseY)))
		{
			intptr_t id = 0;
			this->handleTouchesBegin(1, &id, &_mouseX, &_mouseY);
		}
	}
	else if (isLup)
	{
		if (_captured)
		{
			_captured = false;
			intptr_t id = 0;
			this->handleTouchesEnd(1, &id, &_mouseX, &_mouseY);
		}
	}

	auto _dispatcher = Director::getInstance()->getEventDispatcher();
	if (isLdown || isMdown || isRdown)
	{
		EventMouse event(EventMouse::MouseEventType::MOUSE_DOWN);
		event.setCursorPosition(cursorX, cursorY);
		EventMouse::MouseButton button = EventMouse::MouseButton::BUTTON_MIDDLE;
		if (isLdown)
		{
			button = EventMouse::MouseButton::BUTTON_LEFT;
		}
		else if (isRdown)
		{
			button = EventMouse::MouseButton::BUTTON_RIGHT;
		}
		event.setMouseButton(button);
		_dispatcher->dispatchEvent(&event);
	}
	else if (isLup || isMup || isRup)
	{
		EventMouse event(EventMouse::MouseEventType::MOUSE_UP);
		event.setCursorPosition(cursorX, cursorY);
		EventMouse::MouseButton button = EventMouse::MouseButton::BUTTON_MIDDLE;
		if (isLup)
		{
			button = EventMouse::MouseButton::BUTTON_LEFT;
		}
		else if (isRup)
		{
			button = EventMouse::MouseButton::BUTTON_RIGHT;
		}
		event.setMouseButton(button);
		_dispatcher->dispatchEvent(&event);
	}

	if (isMouseMove)
	{
		_mouseX /= this->getFrameZoomFactor();
		_mouseY /= this->getFrameZoomFactor();

		if (_captured)
		{
			intptr_t id = 0;
			this->handleTouchesMove(1, &id, &_mouseX, &_mouseY);
		}

		EventMouse event(EventMouse::MouseEventType::MOUSE_MOVE);
		EventMouse::MouseButton button = EventMouse::MouseButton::BUTTON_UNSET;
		if (gge::Input_IsMousePress(GGEK_LBUTTON))
		{
			button = EventMouse::MouseButton::BUTTON_LEFT;
		}
		else if (gge::Input_IsMousePress(GGEK_MBUTTON))
		{
			button = EventMouse::MouseButton::BUTTON_MIDDLE;
		}
		else if (gge::Input_IsMousePress(GGEK_RBUTTON))
		{
			button = EventMouse::MouseButton::BUTTON_RIGHT;
		}
		event.setMouseButton(button);
		event.setCursorPosition(cursorX, cursorY);
		_dispatcher->dispatchEvent(&event);
	}

	static int scroll = 0; scroll = gge::Input_GetMouseWheel();
	if (scroll)
	{
		EventMouse event(EventMouse::MouseEventType::MOUSE_SCROLL);
		event.setScrollData(0, -(float)scroll);
		event.setCursorPosition(cursorX, cursorY);
		_dispatcher->dispatchEvent(&event);
	}

	// 	if (_isKeyLock)
	// 	{
	// 		return;
	// 	}
	// 	_isKeyLock = true;
	// keep
	static int key = -1; key = gge::Input_GetKey();
	if (key >= 0)
	{
		if (gge::Input_IsKeyDown(key))
		{
			EventKeyboard event(g_keyCodeMap[key], true);
			_dispatcher->dispatchEvent(&event);
		}

	}
	if (gge::Input_IsKeyDown(GGEK_BACKSPACE))
	{
		IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
		_isDeltaBasckspace = 0;
	}
	else if (gge::Input_IsKeyPress(GGEK_BACKSPACE))
	{
		if (Director::getInstance()->getTotalFrames() % 3 == 0)
		{
			if (++_isDeltaBasckspace > 10)
			{
				IMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
			}
		}
	}
	else
	{
		static std::vector<int> keys =
		{
			GGEK_HOME,
			GGEK_DELETE,
			GGEK_END,
			GGEK_LEFT,
			GGEK_RIGHT,
			GGEK_ESCAPE,
		};
		for (const auto& k : keys)
		{
			if (gge::Input_IsKeyPress(k) || gge::Input_IsKeyDown(k))
			{
				IMEDispatcher::sharedDispatcher()->dispatchControlKey(g_keyCodeMap[key]);
			}
		}
	}


	static const char *chr = nullptr; chr = gge::Input_GetChar();
	if (chr[0])
	{
		static std::set<std::string> controls =
		{
			gge::Input_GetKeyName(GGEK_UP),
			gge::Input_GetKeyName(GGEK_DOWN),
			gge::Input_GetKeyName(GGEK_LEFT),
			gge::Input_GetKeyName(GGEK_RIGHT),
			gge::Input_GetKeyName(GGEK_DELETE),
			gge::Input_GetKeyName(GGEK_HOME),
			gge::Input_GetKeyName(GGEK_END),
			gge::Input_GetKeyName(GGEK_PGUP),
			gge::Input_GetKeyName(GGEK_PGDN),
			gge::Input_GetKeyName(GGEK_UP),
//			gge::Input_GetKeyName(GGEK_CLEAR),
		};
		if (controls.find(chr) == controls.end())
		{
			IMEDispatcher::sharedDispatcher()->dispatchInsertText(chr, strlen(chr));
		}
	}
}


void GLViewImpl::renderScene(Scene* scene, Renderer* renderer)
{
	if (gge::Graph_BeginScene())
	{
		gge::Graph_Clear(0x00101010);
		GLView::renderScene(scene, renderer);
		gge::Graph_EndScene();
	}
}
